package com.example.demo.controller;

import com.example.demo.util.RedisBloomFilter;
import com.example.demo.util.RedisBloomFilterUtil;
import com.example.demo.util.RedisSentinelUtil;
import com.google.common.base.Stopwatch;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author
 * @since 2019—10-30
 */
@RestController
@Slf4j
public class RedisController {

    @Autowired
    private RedisSentinelUtil redisSentinelUtil;


    @RequestMapping("/addBit")
    public void addBit(String k, Integer fSize, Integer size, Integer bitSize, Integer idfaSize) {

        RedisBloomFilter filter = new RedisBloomFilter(fSize, 0.0001);
        log.info("最优 hash个数" + filter.getNumHashFunctions());
        log.info("最优 bitmap长度" + filter.getBitmapLength());
        log.info("每次bit插入数量 : " + bitSize);
        Stopwatch started = Stopwatch.createStarted();
        log.info("创建idfa个数 : " + size);

        ArrayList<String> list = new ArrayList<>();
        HashSet<Long> set = new HashSet<>();

        for (int i = 0; i < size; i++) {
            list.add(UUID.randomUUID().toString());
        }
        log.info("创建idfa 时间 : " + started.stop().toString());
        started.reset();

        //---------------------------------------------------------
        started.start();
        log.info("插入set ");
        RedisBloomFilterUtil.setOperationsAdd(k + "set", list);
        log.info("插入set 时间 : " + started.stop().toString());
        started.reset();

        //---------------------------------------------------------
        started.start();
        log.info("计算bit");
        list.stream().forEach(idfa -> {

            Collections.addAll(set, filter.getBitIndices(idfa));
        });
        log.info("计算bit时间 : " + started.stop().toString());
        started.reset();

        //---------------------------------------------------------
        log.info("创建bit");
        started.start();
        String bitKey = k + "bit";
        RedisBloomFilterUtil.initBit(bitKey, filter.getBitmapLength());
        log.info("总计数量 : " + set.size());
        RedisBloomFilterUtil.setAllBit(set, bitKey, bitSize);
        log.info("创建bit 时间 : " + started.stop().toString());
        started.reset();

        started.start();
        log.info("创建idfa : " + idfaSize);

        ArrayList<String> idfaList = new ArrayList<>();

        for (int i = 0; i < idfaSize; i++) {
            idfaList.add(UUID.randomUUID().toString());
        }
        log.info("创建idfa 时间 : " + started.stop().toString());
        started.reset();

        log.info("set判断 ");
        started.start();
        String setKey = k + "set";
        int count2 = 0;
        for (int i = 0; i < idfaSize; i++) {
            Boolean member = RedisBloomFilterUtil.setOperationsIsMember(setKey, idfaList.get(i));
            if (member) {
                count2++;
            }
        }
        log.info("set判断存在 count : " + count2);
        log.info("set判断 时间 : " + started.stop().toString());
        started.reset();

        log.info("判断bit ");
        byte[] bytes = bitKey.getBytes();
        started.start();
        int count = 0;
        for (String idfa : idfaList) {
            Long[] longs = filter.getBitIndices(idfa);
            boolean b = RedisBloomFilterUtil.bitMembers(longs, bytes);
            if (b) {
                count++;
            }
        }
        log.info("判断bit 时间 : " + started.stop().toString());
        log.info("bit判断存在 count : " + count);
        log.info("误判率 : " + new BigDecimal(count).divide(new BigDecimal(idfaSize)));
        started.reset();

    }


    @RequestMapping("/addSet")
    public void addSet(String k, Integer fSize, Integer size) {

        RedisBloomFilter filter = new RedisBloomFilter(fSize, 0.0001);
        log.info("最优 hash个数" + filter.getNumHashFunctions());
        log.info("最优 bitmap长度" + filter.getBitmapLength());
        Stopwatch started = Stopwatch.createStarted();
        log.info("创建idfa个数 : " + size);

        ArrayList<String> list = new ArrayList<>();

        for (int i = 0; i < size; i++) {
            list.add(UUID.randomUUID().toString());
        }
        log.info("创建idfa 时间 : " + started.stop().toString());
        started.reset();

        //---------------------------------------------------------
        started.start();
        log.info("插入set ");
        RedisBloomFilterUtil.setOperationsAdd(k + "set", list);
        log.info("插入set 时间 : " + started.stop().toString());
        started.reset();

    }


    @RequestMapping("/testBit")
    public void testBit(String k, Integer size) {
        Stopwatch started = Stopwatch.createStarted();
        log.info("创建idfa : " + size);

        ArrayList<String> list = new ArrayList<>();

        for (int i = 0; i < size; i++) {
            list.add(UUID.randomUUID().toString());
        }
        log.info("创建idfa 时间 : " + started.stop().toString());
        started.reset();

        log.info("判断set ");
        started.start();
        String setKey = k + "set";
        for (int i = 0; i < size; i++) {
            RedisBloomFilterUtil.setOperationsIsMember(setKey, list.get(i));
        }
        log.info("判断set 时间 : " + started.stop().toString());
        started.reset();

        log.info("判断bit ");
        String setBit = k + "bit";
        byte[] bytes = setBit.getBytes();
        started.start();
        for (int i = 0; i < size; i++) {
            //RedisBloomFilterUtil.bitMembers( );
        }
        log.info("判断bit 时间 : " + started.stop().toString());
        started.reset();


    }

    @RequestMapping("/set")
    public String demo(String key, String value) {

        redisSentinelUtil.setValue(key, value);

        return "";
    }

    @RequestMapping("/get")
    public String get(String key) {

        return redisSentinelUtil.getValue(key);
    }

    @RequestMapping("/testAll")
    public void test(String key, String val, Integer size) {

        while (size-- > 0) {
            redisSentinelUtil.setValue(key + size, val + size);
            redisSentinelUtil.getValue(key + size);
        }
    }

    @RequestMapping("/write")
    public void write(String key) {
        redisSentinelUtil.testWrite(key);
    }

    @RequestMapping("/read")
    public void read(String key) {
        redisSentinelUtil.testRead(key);
    }


}
